package iterator;


import java.io.IOException;

import iterator.exceptions.NoOutputBuffer;
import global.GlobalConst;
import heap.Heapfile;
import heap.Tuple;


public class IoBuf extends java.lang.Object implements GlobalConst{

	public static int READ_BUFFER = 1;
	public static int WRITE_BUFFER = 0 ;

	private byte[][] bufs;
	private int tSize;
	private Heapfile temp_fd;
	
	//for flushed variables
	private boolean isDirty;
	private boolean flushed;
	private int currentPageID;
	private int tupplesAtPage;
	private int tupplesAtBuffer;
	private int writtenRecoreds;
	private int readRecored;
	private int mode;
	
	//for get method
	private boolean done;
	private SpoofIbuf iBuffer;
	
	//constants
	private int numberOfTupplesAtBuffer;
	private int numberOfTupplesAtPage;
	
	//Constructor
	public IoBuf() 
	{

	}

	
	//Initialize some necessary inormation, call Iobuf to create the object, and call init to finish instantiation
	public void init(byte[][] bufs, int n_pages, int tSize, Heapfile temp_fd) 
	{
		 this.bufs =bufs;
		 this.tSize = tSize;
		 this.temp_fd = temp_fd;
		 isDirty = false;
		 flushed = false;
		 currentPageID=0;
		 tupplesAtPage=0;
		 tupplesAtBuffer=0;
		 writtenRecoreds=0;
		 readRecored=0;
		 mode = WRITE_BUFFER;
		 done =false;
		 iBuffer = new SpoofIbuf();
		 numberOfTupplesAtBuffer =numberOfTupplesAtPage*n_pages;
		 numberOfTupplesAtPage = MINIBASE_PAGESIZE /tSize;
	}
	
	
	/**
	 * Writes a tuple to the output buffer
	 *@param buf the tuple written to buffer
	 *@exception NoOutputBuffer the buffer is a input bufer now
	 *@exception IOException  some I/O fault
	 *@exception Exception  other exceptions
	 */
	public void Put(Tuple buf) throws NoOutputBuffer, java.io.IOException,java.lang.Exception 
	{
		if(mode == WRITE_BUFFER)
		{
			  throw new NoOutputBuffer("IoBuf:Trying to write to io buffer when it is acting as a input buffer");
		}
		byte[] data = buf.getTupleByteArray();
		System.arraycopy(data, 0,bufs[currentPageID],tSize*tupplesAtPage, tSize);
		tupplesAtPage++;
		writtenRecoreds++;
		tupplesAtBuffer++;
		isDirty = true;
		if(tupplesAtBuffer == numberOfTupplesAtBuffer)
		{
			flush();
			tupplesAtPage=0;
			tupplesAtBuffer=0;
			currentPageID=0;
		}
		else if(tupplesAtPage == numberOfTupplesAtPage)
		{
			tupplesAtPage=0;
			currentPageID++;
		}
	}

	
	public Tuple Get(Tuple buf) throws java.io.IOException, java.lang.Exception 
	{
		if(done)
		{
			buf = null;
		}
		else
		{
			//change the mode of the buffer
			if(mode == WRITE_BUFFER)
			{
				reread();
			}
			//all records on the disk now
			if(flushed)
			{
				Tuple next =  iBuffer.Get(buf);
				if(next == null)
				{
					done = true;
				}
			}
			//read from the bool;
			else
			{
				if((currentPageID*numberOfTupplesAtPage+ readRecored)==writtenRecoreds)
				{
					done = true;
					buf = null;
				}
				else
				{
					buf.tupleSet(bufs[currentPageID],readRecored*tSize, tSize); 
					readRecored++;
					if(readRecored == numberOfTupplesAtPage)
					{
						readRecored=0;
						currentPageID++;
					}
				}
			}
		}
		return buf;
	}

	
	//returns the numbers of tuples written 
	//check the buffer mode if it write or read if read do nothing"error"
	//else it is on write mode so 
	//check the buffer if it have data not written go and write it 
	//else make it true;
	public long flush()throws java.io.IOException,java.lang.Exception
	{
		if(isDirty)
		{
			byte[] data = new byte[tSize];
			for(int i=0;i<=currentPageID;i++)
			{
				for(int j=0;j<tupplesAtPage;j++)
				{
					System.arraycopy(bufs[i],tSize*j,data,0,tSize);
					try
					{
					   temp_fd.insertRecord(data);
					}
					catch(Exception e)
					{
						throw e;
					}
				}
			}
			isDirty = false;
			flushed = true;
		}
		return writtenRecoreds;
	}
	
	
	//if WRITE_BUFFER is true, call this mehtod to switch to read buffer.
	// this method assumed when call that it is in write mode
	public void reread() throws java.io.IOException, java.lang.Exception 
	{
		//ana 3ande 2 mode read or write 
		//we ana hena aked ana fe wirte mode we 3awza a3'ayaro 
		//atcheck an el mode wirte
		//law write ashofe kol el pages ely lesa mesh maktoba 
		// a3mel flush lekol el pages then close them 
		//chande the mode o write;
	}
	
	

}
